/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Text;

using Microsoft.Xna.Framework.Content.Pipeline;

namespace Cobalt.Content.Pipeline.Graphics.Font
{
	public class SpriteFontDescription : ContentItem
	{
		#region PointSizeCollection and CharacterCollection
		public class PointSizeCollection : ICollection<float>
		{
			internal PointSizeCollection() { }

			private Dictionary<float, float> sizeSet = new Dictionary<float, float>();

			public void Add( float item )
			{
				if( item < 1 )
					throw new ArgumentOutOfRangeException( "item" );

				sizeSet[item] = item;
			}

			public void AddRange( IEnumerable<float> items )
			{
				if( items == null )
					throw new ArgumentNullException( "items" );

				foreach( float size in items )
					Add( size );
			}

			public void Clear()
			{
				sizeSet.Clear();
			}

			public bool Contains( float item )
			{
				return sizeSet.ContainsKey( item );
			}

			void ICollection<float>.CopyTo( float[] array, int arrayIndex )
			{
				sizeSet.Keys.CopyTo( array, arrayIndex );
			}

			public int Count
			{
				get { return sizeSet.Count; }
			}

			bool ICollection<float>.IsReadOnly
			{
				get { return false; }
			}

			public bool Remove( float item )
			{
				return sizeSet.Remove( item );
			}

			public IEnumerator<float> GetEnumerator()
			{
				return sizeSet.Keys.GetEnumerator();
			}

			System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			internal float[] GetSizeList()
			{
				float[] ret = new float[sizeSet.Count];

				sizeSet.Keys.CopyTo( ret, 0 );
				Array.Sort( ret );

				return ret;
			}
		}

		public class CharacterCollection : ICollection<int>, ICollection<char>
		{
			internal CharacterCollection() { }

			private static readonly char[] DefaultCharacters;
			static CharacterCollection()
			{
				List<char> chars = new List<char>();

				chars.AddRange( " \"'\\/~!@#$%^&*()_+-=|[]{};:,.<>?`".ToCharArray() );
				for( char c = 'a'; c <= 'z'; c++ )
					chars.Add( c );
				for( char c = 'A'; c <= 'Z'; c++ )
					chars.Add( c );
				for( char c = '0'; c <= '9'; c++ )
					chars.Add( c );

				DefaultCharacters = chars.ToArray();
			}

			public void AddDefaultCharacters()
			{
				AddRange( DefaultCharacters );
			}

			public bool HasDefaultCharacters()
			{
				foreach( char ch in DefaultCharacters )
					if( !charSet.ContainsKey( ch ) )
						return false;

				return true;
			}

			private Dictionary<int, int> charSet = new Dictionary<int, int>();

			public int Count { get { return charSet.Count; } }
			bool ICollection<char>.IsReadOnly { get { return false; } }
			bool ICollection<int>.IsReadOnly { get { return false; } }

			public void Add( char item )
			{
				charSet[item] = item;
			}

			public void Add( int item )
			{
				charSet[item] = item;
			}

			public void AddRange( IEnumerable<char> items )
			{
				if( items == null )
					throw new ArgumentNullException( "items" );

				foreach( char ch in items )
					charSet[ch] = ch;
			}

			public void AddRange( IEnumerable<int> items )
			{
				if( items == null )
					throw new ArgumentNullException( "items" );

				foreach( int ch in items )
					charSet[ch] = ch;
			}

			public void Clear()
			{
				charSet.Clear();
			}

			public bool Contains( char item )
			{
				return charSet.ContainsKey( item );
			}

			public bool Contains( int item )
			{
				return charSet.ContainsKey( item );
			}

			void ICollection<char>.CopyTo( char[] array, int arrayIndex )
			{
				if( array == null )
					throw new ArgumentNullException( "array" );
				if( arrayIndex < 0 || arrayIndex + charSet.Keys.Count > array.Length )
					throw new ArgumentOutOfRangeException( "arrayIndex" );

				int c = arrayIndex;
				foreach( int i in charSet.Keys )
					array[c++] = (char)i;
			}

			void ICollection<int>.CopyTo( int[] array, int arrayIndex )
			{
				charSet.Keys.CopyTo( array, arrayIndex );
			}

			IEnumerator<char> IEnumerable<char>.GetEnumerator()
			{
				foreach( int ch in charSet.Keys )
					yield return (char)ch;
			}

			public IEnumerator<int> GetEnumerator()
			{
				return charSet.Keys.GetEnumerator();
			}

			public bool Remove( char item )
			{
				return charSet.Remove( item );
			}

			public bool Remove( int item )
			{
				return charSet.Remove( item );
			}

			System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}

			internal int[] GetCharList()
			{
				int[] ret = new int[charSet.Count];

				charSet.Keys.CopyTo( ret, 0 );
				Array.Sort( ret );

				return ret;
			}
		}
		#endregion

		private string fontName = string.Empty;
		/// <summary>
		/// Gets or sets the font name.
		/// </summary>
		public string FontName
		{
			get { return fontName; }
			set { fontName = value ?? string.Empty; }
		}

		private FontStyle style = FontStyle.Regular;
		/// <summary>
		/// Gets or sets the font style.
		/// </summary>
		public FontStyle Style
		{
			get { return style; }
			set { style = value; }
		}

		private PointSizeCollection sizes = new PointSizeCollection();
		/// <summary>
		/// Gets the list of sizes at which to render the font.
		/// </summary>
		public PointSizeCollection Sizes { get { return sizes; } }

		private CharacterCollection characters = new CharacterCollection();
		/// <summary>
		/// Gets the list of characters to include in the font.
		/// </summary>
		public CharacterCollection Characters { get { return characters; } }

		private Size maxImageSize = new Size( 256, 256 );
		/// <summary>
		/// Gets or sets the maximum sprite sheet image size.
		/// </summary>
		/// <remarks>
		/// This value must be at least 64 x 64, and both
		/// dimensions must be a power of 2.
		/// </remarks>
		public Size MaxImageSize
		{
			get { return maxImageSize; }
			set
			{
				if( value.Width < 64 || value.Height < 64 )
					throw new ArgumentOutOfRangeException( "MaxImageSize", "MaxImageSize must be at least 64 x 64." );

				if( !Helpers.IsPowerOf2( value.Width ) ||
					!Helpers.IsPowerOf2( value.Height ) )
					throw new ArgumentException( "Image dimensions must be powers of 2." );

				maxImageSize = value;
			}
		}
	}	
}